#include "abaqus_inp_parser.h"
#include <iostream>
#include <algorithm>
#include <sstream>

// Block parsing method implementations
void AbaqusInpParser::parseNodeBlock(const std::vector<std::string>& lines, size_t& i) {
    std::vector<std::pair<int, std::vector<float>>> node_data;
    
    i++; // Skip *Node line
    while (i < lines.size()) {
        const std::string& line = lines[i];
        
        // Check for new section
        if (!line.empty() && line[0] == '*') {
            break;
        }
        
        // Skip empty lines and comments
        if (line.empty() || (line.length() >= 2 && line[0] == '*' && line[1] == '*')) {
            i++;
            continue;
        }
        
        // Convert whitespace to commas for mixed delimiter support
        std::string processed_line = line;
        for (char& ch : processed_line) {
            if (std::isspace(static_cast<unsigned char>(ch))) {
                ch = ',';
            }
        }
        
        // Parse node data
        std::istringstream iss(processed_line);
        std::string token;
        std::vector<std::string> tokens;
        
        while (std::getline(iss, token, ',')) {
            token.erase(0, token.find_first_not_of(" \t"));
            token.erase(token.find_last_not_of(" \t") + 1);
            if (!token.empty()) {
                tokens.push_back(token);
            }
        }
        
        if (tokens.size() >= 4) {
            try {
                int node_id = std::stoi(tokens[0]);
                std::vector<float> coords(3);
                for (int j = 0; j < 3; j++) {
                    coords[j] = std::stof(tokens[j + 1]);
                }
                node_data.emplace_back(node_id, coords);
            } catch (const std::exception& e) {
                std::cerr << "Node data parsing error: " << e.what() << ", line: " << line << std::endl;
            }
        }
        
        i++;
    }
    
    // Process node data
    if (node_data.empty()) return;
    
    // Sort by node ID
    std::sort(node_data.begin(), node_data.end(), 
              [](const auto& a, const auto& b) { return a.first < b.first; });
    
    // Create node array
    Matrix<float> node_array(node_data.size(), 3);
    for (size_t idx = 0; idx < node_data.size(); idx++) {
        const auto& node = node_data[idx];
        for (int j = 0; j < 3; j++) {
            node_array(idx, j) = node.second[j];
        }
        current_part->addNodeMapping(node.first, idx);
    }
    current_part->setNodeArray(node_array);
}

void AbaqusInpParser::parseElementBlock(const std::vector<std::string>& lines, size_t& i) {
    std::vector<std::pair<int, std::vector<int>>> elem_data;
    
    i++; // Skip *Element line
    while (i < lines.size()) {
        const std::string& line = lines[i];
        
        // Check for new section
        if (!line.empty() && line[0] == '*') {
            break;
        }
        
        // Skip comments
        if (line.length() >= 2 && line[0] == '*' && line[1] == '*') {
            i++;
            continue;
        }
        
        // Convert whitespace to commas for mixed delimiter support
        std::string processed_line = line;
        for (char& ch : processed_line) {
            if (std::isspace(static_cast<unsigned char>(ch))) {
                ch = ',';
            }
        }
        
        // Parse element data
        std::istringstream iss(processed_line);
        std::string token;
        std::vector<std::string> tokens;
        
        while (std::getline(iss, token, ',')) {
            token.erase(0, token.find_first_not_of(" \t"));
            token.erase(token.find_last_not_of(" \t") + 1);
            if (!token.empty()) {
                tokens.push_back(token);
            }
        }
        
        if (tokens.size() >= 2) {
            try {
                int elem_id = std::stoi(tokens[0]);
                std::vector<int> nodes;
                for (size_t j = 1; j < tokens.size(); j++) {
                    nodes.push_back(std::stoi(tokens[j]));
                }
                elem_data.emplace_back(elem_id, nodes);
            } catch (const std::exception& e) {
                std::cerr << "Element data parsing error: " << e.what() << ", line: " << line << std::endl;
            }
        }
        
        i++;
    }
    
    // Process element data
    if (elem_data.empty()) {
        std::cerr << "Warning: Empty element data" << std::endl;
        return;
    }
    
    // Sort by element ID
    std::sort(elem_data.begin(), elem_data.end(),
              [](const auto& a, const auto& b) { return a.first < b.first; });
    
    // Determine element node count
    int elem_nodes = elem_data[0].second.size();
    
    // Create element array
    Matrix<int> elem_array(elem_data.size(), elem_nodes);
    for (size_t idx = 0; idx < elem_data.size(); idx++) {
        const auto& elem = elem_data[idx];
        for (int j = 0; j < elem_nodes && j < elem.second.size(); j++) {
            elem_array(idx, j) = elem.second[j];
        }
        current_part->addElemInfo(elem.first, current_elem_type, idx);
    }
    
    current_part->addElemType(current_elem_type, elem_array);
}

std::string AbaqusInpParser::parseElementType(const std::string& line) {
    size_t pos = line.find("type=");
    if (pos == std::string::npos) {
        pos = line.find("TYPE=");
    }
    if (pos != std::string::npos) {
        std::string type_str = line.substr(pos + 5);
        size_t comma_pos = type_str.find(',');
        if (comma_pos != std::string::npos) {
            type_str = type_str.substr(0, comma_pos);
        }
        type_str.erase(0, type_str.find_first_not_of(" \t"));
        type_str.erase(type_str.find_last_not_of(" \t") + 1);
        return type_str;
    }
    return "UNKNOWN";
}

std::vector<float> AbaqusInpParser::parseTranslate(const std::string& line) {
    std::vector<float> translate(3, 0.0f);
    std::istringstream iss(line);
    std::string token;
    
    for (int i = 0; i < 3 && std::getline(iss, token, ','); i++) {
        try {
            token.erase(0, token.find_first_not_of(" \t"));
            token.erase(token.find_last_not_of(" \t") + 1);
            if (!token.empty()) {
                translate[i] = std::stof(token);
            }
        } catch (const std::exception& e) {
            // Use default value 0.0
        }
    }
    
    return translate;
}

std::vector<std::vector<float>> AbaqusInpParser::parseRotate(const std::string& line) {
    std::vector<std::vector<float>> rotation;
    std::vector<float> values;
    std::istringstream iss(line);
    std::string token;
    
    while (std::getline(iss, token, ',')) {
        try {
            token.erase(0, token.find_first_not_of(" \t"));
            token.erase(token.find_last_not_of(" \t") + 1);
            if (!token.empty()) {
                values.push_back(std::stof(token));
            }
        } catch (const std::exception& e) {
            // Ignore error
        }
    }
    
    if (values.size() >= 7) {
        std::vector<float> axis_point1(values.begin(), values.begin() + 3);
        std::vector<float> axis_point2(values.begin() + 3, values.begin() + 6);
        std::vector<float> angle = { values[6] };
        
        rotation.push_back(axis_point1);
        rotation.push_back(axis_point2);
        rotation.push_back(angle);
    }
    
    return rotation;
}